package com.uobgroup.ews.uam.web;

import java.io.UnsupportedEncodingException;
import java.security.Principal;
import java.util.Arrays;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import org.apache.commons.lang.StringUtils;
import org.joda.time.format.DateTimeFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.util.UriUtils;
import org.springframework.web.util.WebUtils;

import com.uobgroup.ews.uam.core.domain.AccessControl;
import com.uobgroup.ews.uam.core.domain.CombinationType;
import com.uobgroup.ews.uam.core.exception.CannotDeleteObjectException;
import com.uobgroup.ews.uam.core.service.AccessControlService;

@RequestMapping("/accesscontrols")
@Controller
public class AccessControlController {

   @Autowired
   private AccessControlService accessControlService;

   @Autowired
   private ReloadableResourceBundleMessageSource messageSource;

   private String m_aclName = "";

   private boolean isShow = true;

   @RequestMapping(method = RequestMethod.POST, produces = "text/html")
   public String create(@Valid AccessControl accessControl, BindingResult bindingResult, Model uiModel,
         HttpServletRequest httpServletRequest, Principal principal) {

      if (!StringUtils.isAlphaSpace(accessControl.getName())) {
         bindingResult.addError(new ObjectError("name", new String[] { "field_invalid_alpha_space" },
               new String[] { messageSource.getMessage("label_com_uobgroup_ews_uam_core_domain_accesscontrol_name",
                     null, null) }, ""));
      }
      if (bindingResult.hasErrors()) {
         populateEditForm(uiModel, accessControl);
         return "accesscontrols/create";
      }

      List<String> lstACLName = accessControlService.findAllACLName();
      String aclName = accessControl.getName();
      if (lstACLName.contains(aclName)) {
         populateEditForm(uiModel, accessControl);
         uiModel.addAttribute("messageError", messageSource.getMessage("field_unique", new String[] { aclName }, null));
         return "accesscontrols/create";
      }

      uiModel.asMap().clear();
      accessControl.setLastModificationUserId(principal.getName());
      trimProperties(accessControl);

      accessControlService.saveAccessControl(accessControl);
      return "redirect:/accesscontrols/view/"
            + encodeUrlPathSegment(accessControl.getId().toString(), httpServletRequest);
   }

   @RequestMapping(value = "/create", produces = "text/html", method = RequestMethod.GET)
   public String createForm(Model uiModel) {
      populateEditForm(uiModel, new AccessControl());
      return "accesscontrols/create";
   }

   @RequestMapping(value = "/view/{id}", produces = "text/html", method = RequestMethod.GET)
   public String show(@PathVariable("id") Long id, Model uiModel) {
      if (isShow == false && accessControlService.isACLInUse(id)) {
         uiModel.addAttribute("messageError",
               messageSource.getMessage("field_cannot_update", new Object[] { "this ACL" }, null));
         isShow = true;
      }
      addDateTimeFormatPatterns(uiModel);
      uiModel.addAttribute("accesscontrol", accessControlService.findAccessControl(id));
      uiModel.addAttribute("itemId", id);
      return "accesscontrols/show";
   }

   @RequestMapping(produces = "text/html")
   public String list(@RequestParam(value = "page", required = false) Integer page,
         @RequestParam(value = "size", required = false) Integer size, Model uiModel,
         @ModelAttribute("error") final String error) {
      String forward = listACLs(page, size, uiModel);
      uiModel.addAttribute("deleteMessageError", error);
      return forward;
   }

   @RequestMapping(method = RequestMethod.PUT, produces = "text/html")
   public String update(@Valid AccessControl accessControl, BindingResult bindingResult, Model uiModel,
         HttpServletRequest httpServletRequest, Principal principal, final RedirectAttributes redirectAttrs) {
      
      AccessControl acl = accessControlService.findAccessControl(accessControl.getId());
      if (null == acl) {
         redirectAttrs.addFlashAttribute("error", messageSource.getMessage("entity_not_found_single",
                     new String[] { messageSource.getMessage("label_com_uobgroup_ews_uam_core_domain_accesscontrol", null, null) }, "", null));
         redirectAttrs.addAttribute("page", "1");
         redirectAttrs.addAttribute("size", "10");
         return "redirect:/accesscontrols";
      }
      if (bindingResult.hasErrors()) {
         populateEditForm(uiModel, accessControl);
         return "accesscontrols/update";
      }

      if (!accessControlService.isACLInUse(accessControl.getId())) {
         List<String> lstACLName = accessControlService.findAllACLName();
         String aclName = accessControl.getName();
         if (!aclName.equals(m_aclName) && lstACLName.contains(aclName)) {
            populateEditForm(uiModel, accessControl);
            uiModel.addAttribute("messageError",
                  messageSource.getMessage("field_unique", new String[] { aclName }, null));
            return "accesscontrols/update";
         }

         uiModel.asMap().clear();
         accessControl.setLastModificationUserId(principal.getName());
         accessControlService.updateAccessControl(accessControl);
      }

      isShow = false;
      return "redirect:/accesscontrols/view/"
            + encodeUrlPathSegment(accessControl.getId().toString(), httpServletRequest);
   }

   @RequestMapping(value = "/update/{id}", produces = "text/html", method = RequestMethod.GET)
   public String updateForm(@PathVariable("id") Long id, Model uiModel, final RedirectAttributes redirectAttrs) {
      AccessControl acl = accessControlService.findAccessControl(id);
      if (null == acl) {
         redirectAttrs.addFlashAttribute("error", messageSource.getMessage("entity_not_found_single",
                     new String[] { messageSource.getMessage("label_com_uobgroup_ews_uam_core_domain_accesscontrol", null, null) }, "", null));
         redirectAttrs.addAttribute("page", "1");
         redirectAttrs.addAttribute("size", "10");
         return "redirect:/accesscontrols";
      }
      m_aclName = acl.getName();
      populateEditForm(uiModel, acl);
      return "accesscontrols/update";
   }

   @RequestMapping(value = "/{id}", method = RequestMethod.DELETE, produces = "text/html")
   public String delete(@PathVariable("id") Long id, @RequestParam(value = "page", required = false) Integer page,
         @RequestParam(value = "size", required = false) Integer size, Model uiModel, Principal principal, final RedirectAttributes redirectAttrs) {
      AccessControl accessControl = accessControlService.findAccessControl(id);
      String forward = "";
      if (accessControl != null) {
         if (accessControlService.isACLInUse(id)) {
            uiModel
                  .addAttribute("deleteMessageError", messageSource.getMessage("field_cannot_delete", new Object[] {}, null));
            // if (page != null || size != null) {
            int sizeNo = size == null ? 10 : size.intValue();
            final int firstResult = page == null ? 0 : (page.intValue() - 1) * sizeNo;
            uiModel.addAttribute("accesscontrols", accessControlService.findAccessControlEntries(firstResult, sizeNo));
            float nrOfPages = (float) accessControlService.countAllAccessControls() / sizeNo;
            uiModel.addAttribute("maxPages", (int) ((nrOfPages > (int) nrOfPages || nrOfPages == 0.0) ? nrOfPages + 1
                  : nrOfPages));
            /*
             * } else { uiModel.addAttribute("accesscontrols",
             * accessControlService.findAllAccessControls()); }
             */
            return "accesscontrols/list";
         }
         else {
            String errorMessageKey = null;
            try {
               accessControl.setLastModificationUserId(principal.getName());
               accessControlService.deleteAccessControl(accessControl);
               uiModel.asMap().clear();
            }
            catch (CannotDeleteObjectException e) {
               errorMessageKey = e.getMessage();
            }
            if (errorMessageKey != null) {
               uiModel.addAttribute("messageError", messageSource.getMessage(errorMessageKey,
                     new String[] { accessControl.getName() }, "CannotDeleteObjectException", null));
            }
            forward = listACLs((page == null) ? 1 : page, (size == null) ? 10 : size, uiModel);
         }
      } else {
         redirectAttrs.addFlashAttribute("error", messageSource.getMessage("entity_not_found_single", new String[] {messageSource.getMessage("label_com_uobgroup_ews_uam_core_domain_accesscontrol", null, null)}, null));
         redirectAttrs.addAttribute("page", "1");
         redirectAttrs.addAttribute("size", "10");
         return "redirect:/accesscontrols";
      }

      return forward;
   }

   private String listACLs(Integer page, Integer size, Model uiModel) {
      // if (page != null || size != null) {
      int sizeNo = size == null ? 10 : size.intValue();
      final int firstResult = page == null ? 0 : (page.intValue() - 1) * sizeNo;
      uiModel.addAttribute("accesscontrols", accessControlService.findAccessControlEntries(firstResult, sizeNo));
      float nrOfPages = (float) accessControlService.countAllAccessControls() / sizeNo;
      uiModel.addAttribute("maxPages", (int) ((nrOfPages > (int) nrOfPages || nrOfPages == 0.0) ? nrOfPages + 1
            : nrOfPages));
      /*
       * } else { uiModel.addAttribute("accesscontrols",
       * accessControlService.findAllAccessControls()); }
       */
      addDateTimeFormatPatterns(uiModel);
      return "accesscontrols/list";
   }

   void addDateTimeFormatPatterns(Model uiModel) {
      uiModel.addAttribute("accessControl_modificationdate_date_format",
            DateTimeFormat.patternForStyle("M-", LocaleContextHolder.getLocale()));
   }

   void populateEditForm(Model uiModel, AccessControl accessControl) {
      uiModel.addAttribute("accessControl", accessControl);
      uiModel.addAttribute("combinationtypes", Arrays.asList(CombinationType.values()));
      addDateTimeFormatPatterns(uiModel);
   }

   String encodeUrlPathSegment(String pathSegment, HttpServletRequest httpServletRequest) {
      String enc = httpServletRequest.getCharacterEncoding();
      if (enc == null) {
         enc = WebUtils.DEFAULT_CHARACTER_ENCODING;
      }
      try {
         pathSegment = UriUtils.encodePathSegment(pathSegment, enc);
      }
      catch (UnsupportedEncodingException uee) {
      }
      return pathSegment;
   }

   @RequestMapping(value = "/test", produces = "text/html", method = RequestMethod.GET)
   public String gettest(Model uiModel) {
      populateEditForm(uiModel, new AccessControl());
      return "accesscontrols/test";
   }

   void trimProperties(AccessControl accessControl) {
      accessControl.setDescription(accessControl.getDescription().trim());
      accessControl.setName(accessControl.getName().trim());
   }
}
